#pragma once

#include "ThreadCache.hpp"
// #include <unistd.h>//debug

// 整个项目的目的就是要让内存池支持高并发的功能
// 而需要调用的接口就两个 ConcurrentAlloc(用于申请空间), ConcurrentFree(用于释放空间)

void *ConcurrentAlloc(size_t size) // 线程用这个接口来申请空间
{
    // cout << "debug ConcurrentAlloc begin" << endl;
    // cout << getpid() << " " << p_tls_thread_cache << endl; // debug：把对应的线程id和申请到的空间地址输出到屏幕上
    if (size > MAX_BYTES)
    {
        size_t align_size = SizeClass::RoundUp(size); // 计算出对齐后的大小
        size_t k = align_size >> PAGE_SHIFT;          // 计算出需要的页数

        PageCache::GetInstance()->_mtx.lock();             // 对PageCache进行操作，这时候需要上锁
        Span *span = PageCache::GetInstance()->NewSpan(k); // 直接向PageCache获得k页的空间
        span->_obj_size = size;                            // 记录这页中块的大小
        PageCache::GetInstance()->_mtx.unlock();           // 解锁
        void *ptr = (void *)(span->_page_id << PAGE_SHIFT);// 通过页号直接获得空间

        return ptr;
    }
    else
    {
        if (p_tls_thread_cache == nullptr)
        {
            // p_tls_thread_cache = new ThreadCache;
            //要想脱离malloc，这里也就不要使用new，而是使用之前的定长内存池这个组件

            static ObjectPool<ThreadCache> obj_pool;//使用静态的方式
            //防止产生线程安全的问题:选择在这里加锁的原因是
            //这个线程安全的问题只会在这里产生
            //假如在ObjectPool<T>::New里面进行加锁的话
            //后面的PageCache中多次的New的操作会影响效率
            obj_pool._pool_mtx.lock();
            p_tls_thread_cache = obj_pool.New();
            obj_pool._pool_mtx.unlock();
        }
        return p_tls_thread_cache->Allocate(size);
    }
    // cout << "debug ConcurrentAlloc end" << endl;
}

void ConcurrentFree(void *ptr/*, size_t size*/) // 用于释放空间
{
    assert(ptr);

    Span* span = PageCache::GetInstance()->MapObjectToSpan(ptr);
    size_t size = span->_obj_size;//通过映射来寻找size的大小

    if (size > MAX_BYTES)
    {
        //通过MapObjectToSpan找到对应的span
        Span* span = PageCache::GetInstance()->MapObjectToSpan(ptr);
        // cout << span->_n << endl;//test

        //对PageCache进行操作，PageCache整体上锁
        PageCache::GetInstance()->_mtx.lock();
        PageCache::GetInstance()->ReleaseSpanToPageCache(span);
        PageCache::GetInstance()->_mtx.unlock();
    }
    else
    {
        p_tls_thread_cache->Deallocate(ptr, size);
    }
}